﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Cofe.Core;
using Cofe.Core.Filter;
using Cofe.Core.Interfaces;
using Cofe.Core.Property;
using Cofe.Core.Service;
using Cofe.Data.Implements;

namespace Cofe.Data
{
    public class UserFeedbackPropertyProvider : DBPropertyProviderBase
    {
        #region Factory
        [Export(typeof(ICofeService))]
        [ServicePriority(ServicePriorityAttribute.DefaultPriority_COFEDB)]
        public class Factory : ISecondaryPropertyProviderFactory, INotifyImported
        {
            public IEnumerable<IPropertyProvider> GetSecoondaryPropertyProviders(IPropertyHost propertyHost)
            {
                if (_repositoryFactory != null &&
                    !(propertyHost.SecondaryPropertyProviders.Any((p) => p is UserFeedbackPropertyProvider)))
                    yield return new UserFeedbackPropertyProvider(propertyHost, _repositoryFactory);
            }

            public void OnImported(IServiceLocater serviceLocater)
            {
                _repositoryFactory = serviceLocater.TryFindService<IRepositoryFactory>();
            }

            private IRepositoryFactory _repositoryFactory = null;
            private IServiceLocater _serviceLocater = null;

            public IServiceLocater ServiceLocater
            {
                get { return _serviceLocater ?? CofeServices.ServiceLocater; }
                set { _serviceLocater = value; }
            }



        }
        #endregion

        #region Constructor

        public UserFeedbackPropertyProvider(IPropertyHost propertyHost, IRepositoryFactory repositoryFactory)
            : base(propertyHost, repositoryFactory,
            Cofe.Data.PropertyDefinitions.UserFeedbackDefinitions)
        {

            registerDBProperties(UserFeedbackProperties.Description, (dbEntry) => dbEntry.Description, () => null,
                (dbEntry, value) => 
                { 
                    //To-Do: Validate can write.
                    dbEntry.Description = value; return true; 
                });

            registerDBProperties(UserFeedbackProperties.Tags, 
                (r, dbEntry) => 
                    {
                        return new ParameterDic() { TagNamesAsArray = dbEntry.HashTags.Select(ht => ht.TagName).ToArray() }.TagNames;
                    },
                () => "", 
                (r, dbEntry, tagNamesStr) =>
                    {
                        try
                        {
                            var tagNames = new ParameterDic() { TagNames = tagNamesStr }.TagNamesAsArray;
                            var origTagNames = dbEntry.HashTags.Select(ht => ht.TagName);
                            var itemToRemove = origTagNames.SkipWhile(t => tagNames.Contains(t));
                            var itemToAdd = tagNames.Where(t => !origTagNames.Contains(t));
                            r.ModifyHashTag(FilterCollections.FromGuid(dbEntry.Id), itemToAdd.ToArray(), itemToRemove.ToArray());
                            r.SaveChanges();
                            return true;
                        }
                        catch (Exception ex)
                        {
                            CofeServices.Logger.Log(ex);
                            return false;
                        }
                    });

            registerDBAction(UserFeedbackProperties.AddTag, (pd, r) =>
                {
                    Guid entryId = propertyHost.Behaviors.GetProperty<Guid>(CacheProperties.Id);
                    r.ModifyHashTag(FilterCollections.FromGuid(entryId), pd.TagNamesAsArray, null);
                    r.SaveChanges();
                }, true);

            registerDBAction(UserFeedbackProperties.RemoveTag, (pd, r) =>
            {
                Guid entryId = propertyHost.Behaviors.GetProperty<Guid>(CacheProperties.Id);
                r.ModifyHashTag(FilterCollections.FromGuid(entryId), null, pd.TagNamesAsArray);
                r.SaveChanges();
            }, true);
        }

        #endregion

        #region Methods

        #endregion

        #region Public Properties

        /// <summary>
        /// For Debug only.
        /// </summary>
        public ISecondaryPropertyProviderFactory[] SecondaryPropertyProviderFactories { get; set; }

        /// <summary>
        /// For Debug only.
        /// </summary>
        public IPathParser[] PathParsers { get; set; }

        public IEntryConstructor EntryConstructor { get; internal set; }

        #endregion
    }
}
